#pragma once

#include "Constants.h"

static short Bitmap_distributeBlock(char blockBitmap[]) {
    short i, j, find = 0;
    for (i = 0; i < 2 * BLOCK_SIZE; ++i) {
        char ch = blockBitmap[i];
        for (j = 0; j < 8; ++j) {
            if ((ch & 1) == 0) {
                find = True;
                blockBitmap[i] ^= (char) (((unsigned char) 1) << j);
                break;
            }
            ch = (char) (((unsigned char) ch) >> 1);
        }
        if (find) {
            break;
        }
    }
    return find ? i * 8 + j : NOTHING;
}

static void Bitmap_removeBlock(char blockBitmap[], int pos) {
    blockBitmap[pos / 8] ^= (char) (((unsigned char) 1) << (pos % 8));
}

static void Block_fillBlock(char *data) {
    char *content = "ujo2ihirnuhishgfidbgwrwerfdswtr32twgwersohoi------";
    int contentLength = (int) strlen(content);
    int contentPtr = 0;
    for (int i = 0; i < BLOCK_SIZE; ++i) {
        data[i] = content[contentPtr];
        contentPtr = (contentPtr + 1) % contentLength;
    }
}

static void Block_copyBlock(char data[], short srcBlock, short destBlock) {
    for (int i = 0; i < BLOCK_SIZE; ++i) {
        data[destBlock * BLOCK_SIZE + i] = data[srcBlock * BLOCK_SIZE + i];
    }
}

static void Block_copyContent(char data[], Inode *srcInode, Inode *destInode) {
    int fileSize = srcInode->fileSize;
    short srcBlock, destBlock;
    short *srcIndirectBlocks, *destIndirectBlocks;
    if (fileSize > DIRECT_BLOCK_SIZE) {
        srcIndirectBlocks = (short *) (data + srcInode->indirectBlock * BLOCK_SIZE);
        destIndirectBlocks = (short *) (data + destInode->indirectBlock * BLOCK_SIZE);
    }
    for (int i = 0; i < fileSize; ++i) {
        if (i < DIRECT_BLOCK_SIZE) {
            srcBlock = srcInode->directBlocks[i];
            destBlock = destInode->directBlocks[i];
        } else {
            srcBlock = srcIndirectBlocks[i - DIRECT_BLOCK_SIZE];
            destBlock = destIndirectBlocks[i - DIRECT_BLOCK_SIZE];
        }
        Block_copyBlock(data, srcBlock, destBlock);
    }
}

static int Block_getUsed(const char bitmap[]) {
    int res = 0;
    for (int i = 0; i < 2 * BLOCK_SIZE; ++i) {
        unsigned char ch = bitmap[i];
        for (int j = 0; j < 8; ++j) {
            if ((ch & 1) == 1) {
                res++;
            }
            ch >>= 1;
        }
    }
    return res;
}

static void Block_printBlock(char data[], int block) {
    for (int i = 0; i < BLOCK_SIZE; ++i) {
        putchar(data[block * BLOCK_SIZE + i]);
    }
}

static void Block_printContent(char data[], Inode *fileInode) {
    short *fileIndirectBlocks;
    if (fileInode->fileSize > DIRECT_BLOCK_SIZE) {
        fileIndirectBlocks = (short *) (data + fileInode->indirectBlock * BLOCK_SIZE);
    }
    for (int i = 0; i < fileInode->fileSize; ++i) {
        int block;
        if (i < DIRECT_BLOCK_SIZE) {
            block = fileInode->directBlocks[i];
        } else {
            block = fileIndirectBlocks[i - DIRECT_BLOCK_SIZE];
        }
        Block_printBlock(data, block);
    }
    putchar('\n');
}